package modeltool

import (
	"errors"
	"github.com/Sir-yuChen/funAnalyse/global"
	"github.com/sergi/go-diff/diffmatchpatch"
	"go.uber.org/zap"
	"io/ioutil"
	"os"
	"regexp"
	"strings"
	"unicode"
)

// FileCompareAndMerge TODO BUG 不能使用按行比较差异化  重新设计方案
func FileCompareAndMerge(path string, tempPath string) error {

	//一次性读取文件 比较差异化
	tempbytes, err := ioutil.ReadFile(tempPath)
	if err != nil {
		global.GVA_LOG.Error("文件差异化对比,读取临时文件异常",
			zap.String("path", path), zap.String("tempPath", tempPath))
		return err
	}
	if len(tempbytes) == 0 {
		global.GVA_LOG.Error("文件差异化对比,[临时文件]未读取到文件内容",
			zap.String("path", path), zap.String("tempPath", tempPath))
		return err
	}
	bytes, err := ioutil.ReadFile(path)
	if err != nil {
		global.GVA_LOG.Error("文件差异化对比,读取已存在文件异常",
			zap.String("path", path), zap.String("tempPath", tempPath))
		return err
	}
	if len(bytes) == 0 {
		global.GVA_LOG.Error("文件差异化对比,[已存在文件]未读取到文件内容",
			zap.String("path", path), zap.String("tempPath", tempPath))
		return errors.New("文件差异化对比,[已存在文件]未读取到文件内容")
	}
	//处理读取到的字符串
	f := compressStr(string(tempbytes))
	s := compressStr(string(bytes))
	dmp := diffmatchpatch.New()
	content := ""
	//比較差异
	diffMain := dmp.DiffMain(s, f, true)
	mergediff := dmp.DiffCleanupMerge(diffMain)

	for _, diff := range mergediff {
		operation := diff.Type
		text := diff.Text
		var count int
		for _, r := range text {
			if unicode.IsSpace(r) {
				//空白符处理
				count++
			}
		}
		if text == "\t" || text == "\r" || text == "" || len(text) == count {
			//制表符跳过\t 表示将光标的位置回退到本行的开头位置\r
			continue
		}
		//todo Delete场景未实现
		//处理拼接保留的字符串
		switch operation.String() {
		case "Equal":
			content += text
			break
		case "Delete":
			content += text
			break
		case "Insert":
			//content += text  临时文件中新增的部分
			break
		}
	}

	/*
		//按照行读取，比较差异化
		tempbytes, err := ReadFileLine(tempPath)
		if err != nil {
			global.GVA_LOG.Error("文件差异化对比,读取临时文件异常",
				zap.String("path", path), zap.String("tempPath", tempPath))
			return err
		}
		if len(tempbytes) == 0 {
			global.GVA_LOG.Error("文件差异化对比,[临时文件]未读取到文件内容",
				zap.String("path", path), zap.String("tempPath", tempPath))
			return err
		}
		bytes, err := ReadFileLine(path)
		if err != nil {
			global.GVA_LOG.Error("文件差异化对比,读取已存在文件异常",
				zap.String("path", path), zap.String("tempPath", tempPath))
			return err
		}
		if len(bytes) == 0 {
			global.GVA_LOG.Error("文件差异化对比,[已存在文件]未读取到文件内容",
				zap.String("path", path), zap.String("tempPath", tempPath))
			return errors.New("文件差异化对比,[已存在文件]未读取到文件内容")
		}

		dmp := diffmatchpatch.New()
		content := ""
		var size int
		mark := false
		if len(tempbytes) <= len(bytes) {
			size = len(bytes)
		} else {
			size = len(tempbytes)
		}
		for i := 0; i < size; i++ {
			line := ""
			lineTemp := ""
			if i > len(bytes)-1 {
				mark = true
			} else {
				line = bytes[i]
			}
			if i > len(tempbytes)-1 {
				mark = true
			} else {
				lineTemp = tempbytes[i]
			}
			//比較差异
			diffMain := dmp.DiffMain(line, lineTemp, true)
			diffMark := false
			for _, diff := range diffMain {
				if diff.Type.String() == "Delete" && !diffMark {
					content += line
					content += "\n" + lineTemp
					diffMark = true
				}
			}

			for _, diff := range diffMain {
				if diffMark {
					continue
				}
				operation := diff.Type
				text := diff.Text
				var count int
				for _, r := range text {
					if unicode.IsSpace(r) {
						//空白符处理
						count++
					}
				}
				if text == "\t" || text == "\r" || text == "" || len(text) == count {
					//制表符跳过\t 表示将光标的位置回退到本行的开头位置\r
					continue
				}
				if mark {
					if line != "" {
						content += line
					} else {
						content += lineTemp
					}
					diffMark = true
					break
				}
				//处理拼接保留的字符串
				switch operation.String() {
				case "Equal":
					content += text
					break
				case "Insert":
					content += text //临时文件中新增的部分
					break
				}
			}

		}*/
	if content == "" {
		global.GVA_LOG.Error("文件差异化对比,文件内容拼接异常",
			zap.String("path", path), zap.String("tempPath", tempPath))
		return errors.New("文件差异化对比,文件内容拼接异常")
	}
	//写入文件
	err = ioutil.WriteFile(path, []byte(content), 777) //写入文件(字节数组)
	if err != nil {
		global.GVA_LOG.Error("文件差异化对比,写入文件异常",
			zap.String("path", path), zap.String("tempPath", tempPath), zap.Error(err))
		return err
	}
	//删除临时文件 停留几秒在删除 保证文件以及被关闭
	defer func() {
		if err := os.Remove(tempPath); err != nil {
			//如果删除失败则输出 file remove Error!
			global.GVA_LOG.Error("Temp file remove Error",
				zap.String("path", path), zap.String("tempPath", tempPath), zap.Error(err))
			return
		}
	}()
	return err
}

func compressStr(str string) string {
	if str == "" {
		return ""
	}
	re := regexp.MustCompile(`(?m)^\s*$[\r\n]*|[\r\n]+\s+\z`)
	s := re.ReplaceAllString(str, "")

	space := strings.TrimSpace(s)
	//匹配一个或多个空白符的正则表达式
	reg := regexp.MustCompile("\\t+")
	return reg.ReplaceAllString(space, "")
}

// ReadFileLine 全部读取后按换行拆分
func ReadFileLine(path string) ([]string, error) {
	fileHanle, err := os.Open(path)
	if err != nil {
		return nil, err
	}
	readBytes, err := ioutil.ReadAll(fileHanle)
	defer fileHanle.Close()
	if err != nil {
		return nil, err
	}
	results := strings.Split(string(readBytes), "\n")
	return results, err
}
